﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Tweets.Library;
using System.Globalization;
using SharePointStu.SharePoint.Logging;

namespace Noftware.SPArchiveTweets.TweetTimer
{
    /// <summary>
    /// List administration class for tweets and related entities.
    /// </summary>
    public class SPTweetList
    {
        /// <summary>
        /// Name of list to hold Twitter accounts. These are user-populated.
        /// </summary>
        public static readonly string AccountListName = "Twitter Accounts";

        /// <summary>
        /// Name of list of all twitter accounts fetched.
        /// </summary>
        public static readonly string TweetAccountListName = "Archived Twitter Accounts";

        /// <summary>
        /// Name of the list that holds all users and their associated sites.
        /// </summary>
        public static readonly string TweetListName = "Archived Tweets";

        /// <summary>
        /// Name of the list that holds all tweet-related media files.
        /// </summary>
        public static readonly string TweetMediaListName = "Archived Tweet Media";

        /// <summary>
        /// Name of the list that holds all tweet-related hash tags.
        /// </summary>
        public static readonly string TweetHashTagListName = "Archived Tweet HashTags";

        /// <summary>
        /// Name of the list that holds all tweet-related URL's.
        /// </summary>
        public static readonly string TweetUrlListName = "Archived Tweet URLs";

        /// <summary>
        /// Name of the list that holds all tweet-related User Mentions.
        /// </summary>
        public static readonly string TweetUserMentionListName = "Archived Tweet User Mentions";

        /// <summary>
        /// Creates the settings list.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createAccountList(SPWeb web)
        {
            // Create User and Site list and its structure
            web.Lists.Add(SPTweetList.AccountListName, "The source list of all Twitter accounts to archive. Please populate this list with Twitter accounts that you would like archived.", SPListTemplateType.GenericList);
            var list = web.Lists[SPTweetList.AccountListName];
            list.RenameTitleField("Twitter Account Name");
            list.Update();

            // Make new columns visible in default view
            var defaultView = list.DefaultView;
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold the twitter accounts.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createTweetAccountList(SPWeb web)
        {
            web.Lists.Add(SPTweetList.TweetAccountListName, "A list to store all fetched Twitter accounts. Do not modify this list.", SPListTemplateType.PictureLibrary);
            var list = web.Lists[SPTweetList.TweetAccountListName];
            list.Fields.Add("Account Id", SPFieldType.Text, true);
            list.Fields.Add("Name", SPFieldType.Text, true);
            list.Fields.Add("Screen Name", SPFieldType.Text, true);
            list.Fields.Add("Location", SPFieldType.Text, true);
            list.Fields.Add("Profile Image URL", SPFieldType.URL, true);
            list.Fields.Add("Account Created On", SPFieldType.DateTime, true);
            list.Update();

            // Make new columns visible in default view
            var defaultView = list.DefaultView;
            defaultView.ViewFields.Add("Account Id");
            defaultView.ViewFields.Add("Name");
            defaultView.ViewFields.Add("Screen Name");
            defaultView.ViewFields.Add("Location");
            defaultView.ViewFields.Add("Profile Image URL");
            defaultView.ViewFields.Add("Account Created On");
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold the tweets.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createTweetList(SPWeb web)
        {
            var accountList = web.Lists[SPTweetList.TweetAccountListName];

            web.Lists.Add(SPTweetList.TweetListName, "A list to store all fetched tweets. Do not modify this list", SPListTemplateType.GenericList);
            var list = web.Lists[SPTweetList.TweetListName];
            list.Fields.Add("Tweet", SPFieldType.Text, true);
            list.Fields.AddLookup("Account", accountList.ID, true);
            list.RenameTitleField("Tweet Id");
            list.Fields.Add("Was Truncated", SPFieldType.Boolean, true);
            list.Fields.Add("Tweeted On", SPFieldType.DateTime, true);
            list.Update();

            // Make new columns visible in default view
            var defaultView = list.DefaultView;
            defaultView.ViewFields.Add("Tweet");
            defaultView.ViewFields.Add("Account");
            defaultView.ViewFields.Add("Was Truncated");
            defaultView.ViewFields.Add("Tweeted On");
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold each tweet's associated media files.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createMediaList(SPWeb web)
        {
            web.Lists.Add(SPTweetList.TweetMediaListName, "A list to hold media items for each tweet. Do not modify this list", SPListTemplateType.PictureLibrary);
            var spChildList = web.Lists[SPTweetList.TweetMediaListName];

            // Get reference to parent and create lookup column
            var parentTweetList = web.Lists[SPTweetList.TweetListName];
            spChildList.AddLookupColumn(parentTweetList, "Tweet Id", "Tweet Id");

            // Add columns
            spChildList.Fields.Add("Media Id", SPFieldType.Text, true);
            spChildList.Fields.Add("Media Type", SPFieldType.Text, true);
            spChildList.Fields.Add("Media URL", SPFieldType.URL, true);
            spChildList.Fields.Add("Display URL", SPFieldType.Text, true);
            spChildList.Fields.Add("Expanded URL", SPFieldType.URL, true);
            spChildList.Update();

            // Make new columns visible in default view
            var defaultView = spChildList.DefaultView;
            defaultView.ViewFields.Add("Media Id");
            defaultView.ViewFields.Add("Media Type");
            defaultView.ViewFields.Add("Tweet Id");
            defaultView.ViewFields.Add("Media URL");
            defaultView.ViewFields.Add("Display URL");
            defaultView.ViewFields.Add("Expanded URL");
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold the tweet's hashtags.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createHashtagList(SPWeb web)
        {
            // Create list
            web.Lists.Add(SPTweetList.TweetHashTagListName, "A list to store hashtags for tweets. Do not modify this list", SPListTemplateType.GenericList);
            var spChildList = web.Lists[SPTweetList.TweetHashTagListName];

            // Get reference to parent and create lookup column
            var parentTweetList = web.Lists[SPTweetList.TweetListName];
            spChildList.AddLookupColumn(parentTweetList, "Tweet Id", "Tweet Id");

            // Rename Title column
            spChildList.RenameTitleField("Hashtag");
            spChildList.Update();

            // Make new columns visible in default view
            var defaultView = spChildList.DefaultView;
            defaultView.ViewFields.Add("Tweet Id");
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold each tweet's associated URLs.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createUrlList(SPWeb web)
        {
            // Create list
            web.Lists.Add(SPTweetList.TweetUrlListName, "A list to hold URLs for each tweet. Do not modify this list", SPListTemplateType.Links);
            var spChildList = web.Lists[SPTweetList.TweetUrlListName];

            // Get reference to parent and create lookup column
            var parentTweetList = web.Lists[SPTweetList.TweetListName];
            spChildList.AddLookupColumn(parentTweetList, "Tweet Id", "Tweet Id");

            // Add list columns
            spChildList.Fields.Add("Display URL", SPFieldType.Text, true);
            spChildList.Fields.Add("Expanded URL", SPFieldType.URL, true);
            spChildList.Update();

            // Make new columns visible in default view
            var defaultView = spChildList.DefaultView;
            defaultView.ViewFields.Add("Tweet Id");
            defaultView.ViewFields.Add("Display URL");
            defaultView.ViewFields.Add("Expanded URL");
            defaultView.Update();
        }

        /// <summary>
        /// Creates the list to hold the twitter User Mentions.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        private void createUserMentionList(SPWeb web)
        {
            // Create list
            web.Lists.Add(SPTweetList.TweetUserMentionListName, "A list to store all tweet user mentions. Do not modify this list", SPListTemplateType.GenericList);
            var spChildList = web.Lists[SPTweetList.TweetUserMentionListName];

            // Get reference to parent and create lookup column
            var parentTweetList = web.Lists[SPTweetList.TweetListName];
            spChildList.AddLookupColumn(parentTweetList, "Tweet Id", "Tweet Id");

            // Rename Title column
            spChildList.RenameTitleField("Screen Name");

            // Add columns
            spChildList.Fields.Add("User Id", SPFieldType.Text, true);
            spChildList.Fields.Add("Name", SPFieldType.Text, true);
            spChildList.Update();

            // Make new columns visible in default view
            var defaultView = spChildList.DefaultView;
            defaultView.ViewFields.Add("User Id");
            defaultView.ViewFields.Add("Tweet Id");
            defaultView.Update();
        }

        /// <summary>
        /// Deletes all custom list items.
        /// </summary>
        /// <param name="web">Reference to web list.</param>
        public void DeleteAllLists(SPWeb web)
        {
            // Names of list to delete
            var lists = new List<string>();
            lists.Add(SPTweetList.TweetUserMentionListName);
            lists.Add(SPTweetList.TweetUrlListName);
            lists.Add(SPTweetList.TweetHashTagListName);
            lists.Add(SPTweetList.TweetMediaListName);
            lists.Add(SPTweetList.TweetListName);
            lists.Add(SPTweetList.TweetAccountListName);
            lists.Add(SPTweetList.AccountListName);

            foreach (string listName in lists)
            {
                if (DoesListExist(listName, web) == true)
                {
                    var list = web.Lists[listName];
                    if (list != null)
                    {
                        list.DeleteLookupColumns();
                        list.Delete();
                    }
                }
            } // foreach (string listName in lists)
        }

        /// <summary>
        /// Checks to see if each Twitter list is present. If not, it creates them.
        /// </summary>
        /// <param name="web">Reference to the Site.</param>
        public void CreateListsIfNotPresent(SPWeb web)
        {
            // Name of list to create
            string listName;

            // Does the source Account list exist?
            listName = SPTweetList.AccountListName;
            if (DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createAccountList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Account list (source) was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Account list (source) " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweet Account list exist?
            listName = SPTweetList.TweetAccountListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createTweetAccountList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Tweet Account list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweet Account list " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweets list exist?
            listName = SPTweetList.TweetListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createTweetList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Tweets list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweets list " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweet Media list exist?
            listName = SPTweetList.TweetMediaListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createMediaList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Tweet Media list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweet Media list " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweet Hashtag list exist?
            listName = SPTweetList.TweetHashTagListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createHashtagList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Tweet Hashtag list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweet Hashtag list " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweet URL list exist?
            listName = SPTweetList.TweetUrlListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createUrlList(web);
                    Logger.LogInfoLocal(EventId.Error, CategoryId.Error, listName + " Tweet URL list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweet URL list " + listName + ".", ex);
                    throw;
                }
            }

            // Does the Tweet User Mention list exist?
            listName = SPTweetList.TweetUserMentionListName;
            if (this.DoesListExist(listName, web) == false)
            {
                // Create the List
                try
                {
                    createUserMentionList(web);
                    Logger.LogInfoLocal(EventId.Information, CategoryId.None, listName + " Tweet User Mention list was successfully created.");
                }
                catch (Exception ex)
                {
                    Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Unable to create the Tweet User Mention list " + listName + ".", ex);
                    throw;
                }
            }
        }

        /// <summary>
        /// Checks to see if the specified list name is already present.
        /// </summary>
        /// <param name="listName">Name of list.</param>
        /// <param name="web">Reference to Site.</param>
        /// <returns>True if list exists; false if otherwise.</returns>
        public bool DoesListExist(string listName, SPWeb web)
        {
            bool listExists = false;
            try
            {
                var list = web.Lists.TryGetList(listName);
                listExists = (list != null);
            }
            catch (Exception)
            {
                // Suppress error as list does not exist
            }

            return listExists;
        }

        /// <summary>
        /// Parse the name of the image file extension from the http URL.
        /// </summary>
        /// <param name="url">URL to parse.</param>
        /// <returns>File extension only.</returns>
        private string getFileExtensionFromUrl(string url)
        {
            string extension = url;
            if (url.Contains("/") == true)
            {
                int index = url.LastIndexOf(".");
                extension = url.Substring(index);
            }

            return extension;
        }

        /// <summary>
        /// Parse the name of the image filename from the http URL.
        /// </summary>
        /// <param name="url">URL to parse.</param>
        /// <returns>Filename only.</returns>
        private string getFileNameFromUrl(string url)
        {
            string fileName = url;
            if (url.Contains("/") == true)
            {
                int index = url.LastIndexOf("/");
                fileName = url.Substring(index + 1);
            }

            return fileName;
        }

        /// <summary>
        /// Get a file, based on its URL, as an SPFile. The new filename will be based on the specified account name.
        /// The file is added to the list's root folder.
        /// </summary>
        /// <param name="spList">Reference to the list to add the file to.</param>
        /// <param name="account">Twitter account name.</param>
        /// <param name="url">HTTP URL of the file.</param>
        /// <returns>SPFile</returns>
        private SPFile getSPFile(SPList spList, string account, string url)
        {
            var request = new System.Net.WebClient();
            byte[] fileContents = request.DownloadData(url);
            string fileName = account + getFileExtensionFromUrl(url);

            // Add image to SP folder
            var spFile = spList.RootFolder.Files.Add(spList.RootFolder.Url + "/" + fileName, fileContents, true);

            return spFile;
        }

        /// <summary>
        /// Get a file, based on its URL, as an SPFile. It is also added to the list's root folder.
        /// </summary>
        /// <param name="spList">Reference to the list to add the file to.</param>
        /// <param name="url">HTTP URL of the file.</param>
        /// <returns>SPFile</returns>
        private SPFile getSPFile(SPList spList, string url)
        {
            var request = new System.Net.WebClient();
            byte[] fileContents = request.DownloadData(url);
            string fileName = getFileNameFromUrl(url);

            // Add image to SP folder
            var spFile = spList.RootFolder.Files.Add(spList.RootFolder.Url + "/" + fileName, fileContents, true);

            return spFile;
        }

        /// <summary>
        /// Archive all tweets in the designated SharePoint lists.
        /// </summary>
        /// <param name="web">Reference to the site that contains the Tweet-related lists.</param>
        /// <returns>Count of tweets archived.</returns>
        public int ArchiveTweets(SPWeb web)
        {
            int tweetCount = 0;
            var tweetSettings = new TweetSettings();
            string temp;

            temp = AppData.Local.Entries[AppData.INCLUDE_ENTITIES] ?? "true";
            tweetSettings.IncludeEntities = bool.Parse(temp);

            temp = AppData.Local.Entries[AppData.INCLUDE_RETWEETS] ?? "true";
            tweetSettings.IncludeRetweets = bool.Parse(temp);

            temp = AppData.Local.Entries[AppData.TWEET_COUNT] ?? "50";
            tweetSettings.TweetCountToFetch = int.Parse(temp);

            var oauthSettings = new OAuth.OAuthConfig()
            {
                OAuthToken = AppData.Local.Entries[AppData.OAUTH_ACCESS_TOKEN] ?? string.Empty,
                OAuthTokenSecret = AppData.Local.Entries[AppData.OAUTH_ACCESS_TOKEN_SECRET] ?? string.Empty,
                ConsumerKey = AppData.Local.Entries[AppData.OAUTH_CONSUMER_KEY] ?? string.Empty,
                ConsumerSecret = AppData.Local.Entries[AppData.OAUTH_CONSUMER_SECRET] ?? string.Empty,
                OAuthSignatureMethod = "HMAC-SHA1",
                OAuthVersion = "1.0"
            };

            var twitter = new Twitter(oauthSettings);

            // Get a list of all accounts to spider
            var accounts = new List<string>();
            var sourceAccountList = web.Lists.TryGetList(SPTweetList.AccountListName);
            if (sourceAccountList != null && sourceAccountList.ItemCount > 0)
            {
                var listItems = sourceAccountList.Items.Cast<SPListItem>();
                foreach (var listItem in listItems)
                {
                    string account = (string)listItem["Twitter Account Name"];
                    if (account != null)
                    {
                        // Remove the leading "@" symbol
                        if (account.StartsWith("@") == true)
                        {
                            account = account.Substring(1);
                        }
                        accounts.Add(account);
                    }
                }
            } // if (list != null && list.ItemCount > 0)

            // Tweet Account (archived) list
            var spTweetAccountList = web.Lists.TryGetList(SPTweetList.TweetAccountListName);

            // Tweet (archived) list
            var spTweetList = web.Lists.TryGetList(SPTweetList.TweetListName);
            if (spTweetAccountList != null && spTweetList != null)
            {
                bool archiveTwitterAcount;
                foreach (string account in accounts)
                {
                    try
                    {
                        // Check to see if this account has been archived
                        archiveTwitterAcount = !doesArchivedAccountExist(spTweetAccountList, account);

                        // Get all tweets
                        var tweets = twitter.GetTimeline(account, tweetSettings);
                        if (tweets != null)
                        {
                            foreach (var tweet in tweets)
                            {
                                if (archiveTwitterAcount == true && tweet.User != null)
                                {
                                    // Download image and add to SP folder
                                    var spImage = getSPFile(spTweetAccountList, account, tweet.User.ProfileImageUrl);
                                    var spAccountListItem = spImage.Item;
                                    // Add image metadata
                                    spAccountListItem["Account Id"] = tweet.User.Id.ToString();
                                    spAccountListItem["Name"] = tweet.User.Name;
                                    spAccountListItem["Screen Name"] = tweet.User.ScreenName;
                                    spAccountListItem["Title"] = tweet.User.ScreenName;
                                    spAccountListItem["Location"] = tweet.User.Location;
                                    spAccountListItem["Description"] = tweet.User.Description;
                                    spAccountListItem["Profile Image URL"] = tweet.User.ProfileImageUrl;
                                    spAccountListItem["Account Created On"] = tweet.User.CreatedOn;
                                    spAccountListItem["Keywords"] = "twitter," + tweet.User.ScreenName;
                                    spAccountListItem.Update();
                                    spImage.Update();

                                    // Reset flag for next account
                                    archiveTwitterAcount = false;

                                } // if (archiveTwitterAcount == true &&...

                                // Ensure this tweet has not already been archived
                                if (doesArchivedTweetExist(spTweetList, tweet.Id.ToString()) == false)
                                {
                                    tweetCount++;

                                    // Archive tweets
                                    var spTweetListItem = spTweetList.Items.Add();
                                    spTweetListItem["Title"] = tweet.Id.ToString();
                                    var accountLookup = spTweetAccountList.GetLookupValue("Account Id", tweet.User.Id.ToString());
                                    spTweetListItem["Account"] = accountLookup;
                                    spTweetListItem.Update();
                                    spTweetListItem["Tweet"] = tweet.Text;
                                    spTweetListItem["Was Truncated"] = tweet.Truncated;
                                    spTweetListItem["Tweeted On"] = tweet.CreatedOn;
                                    spTweetListItem.Update();

                                    // Hashtags
                                    if (tweet.Entities.HashTagCollection != null)
                                    {
                                        var spHashtagList = web.Lists.TryGetList(SPTweetList.TweetHashTagListName);
                                        if (spHashtagList != null)
                                        {
                                            foreach (var hashtag in tweet.Entities.HashTagCollection)
                                            {
                                                var spHashtagListItem = spHashtagList.Items.Add();
                                                spHashtagListItem["Title"] = hashtag.Text;
                                                var tweetLookup = spTweetList.GetLookupValue("Title", tweet.Id.ToString());
                                                spHashtagListItem["Tweet Id"] = tweetLookup;
                                                spHashtagListItem.Update();
                                            }
                                        }
                                    } // if (tweet.HashTagCollection != null)

                                    // URL's
                                    if (tweet.Entities.UrlCollection != null)
                                    {
                                        var spUrlList = web.Lists.TryGetList(SPTweetList.TweetUrlListName);
                                        if (spUrlList != null)
                                        {
                                            foreach (var url in tweet.Entities.UrlCollection)
                                            {
                                                var spUrlListItem = spUrlList.Items.Add();
                                                spUrlListItem["URL"] = url.Url;
                                                spUrlListItem["Display URL"] = url.DisplayUrl;
                                                spUrlListItem["Expanded URL"] = url.ExpandedUrl;
                                                var tweetLookup = spTweetList.GetLookupValue("Title", tweet.Id.ToString());
                                                spUrlListItem["Tweet Id"] = tweetLookup;
                                                spUrlListItem.Update();
                                            }
                                        }
                                    } // if (tweet.UrlCollection != null)

                                    // Media
                                    if (tweet.Entities.MediaCollection != null)
                                    {
                                        var spMediaList = web.Lists.TryGetList(SPTweetList.TweetMediaListName);
                                        if (spMediaList != null)
                                        {
                                            foreach (var media in tweet.Entities.MediaCollection)
                                            {
                                                // Download image and add to SP folder
                                                var spFile = getSPFile(spMediaList, media.MediaUrl);
                                                var spMediaListItem = spFile.Item;
                                                // Add image metadata
                                                string fileName = getFileNameFromUrl(media.MediaUrl);
                                                spMediaListItem["Title"] = fileName;
                                                spMediaListItem["Media Id"] = media.Id.ToString();
                                                spMediaListItem["Media URL"] = media.MediaUrl;
                                                spMediaListItem["Display URL"] = media.DisplayUrl;
                                                spMediaListItem["Expanded URL"] = media.ExpandedUrl;
                                                spMediaListItem["Media Type"] = media.Type;
                                                //spMediaListItem["URL"] = media.Url;
                                                var tweetLookup = spTweetList.GetLookupValue("Title", tweet.Id.ToString());
                                                spMediaListItem["Tweet Id"] = tweetLookup;
                                                spMediaListItem.Update();
                                                spFile.Update();
                                            }
                                        }
                                    } // if (tweet.MediaCollection != null)

                                    // User Mentions
                                    if (tweet.Entities.UserMentionCollection != null)
                                    {
                                        var spUserMentionList = web.Lists.TryGetList(SPTweetList.TweetUserMentionListName);
                                        if (spUserMentionList != null)
                                        {
                                            foreach (var userMention in tweet.Entities.UserMentionCollection)
                                            {
                                                var spUserMentionListItem = spUserMentionList.Items.Add();
                                                spUserMentionListItem["Title"] = userMention.ScreenName;
                                                spUserMentionListItem["User Id"] = userMention.Id.ToString();
                                                spUserMentionListItem["Screen Name"] = userMention.ScreenName;
                                                var tweetLookup = spTweetList.GetLookupValue("Title", tweet.Id.ToString());
                                                spUserMentionListItem["Tweet Id"] = tweetLookup;
                                                spUserMentionListItem.Update();
                                            }
                                        }
                                    } // if (tweet.UserMentionCollection != null)
                                } // if (doesArchivedTweetExist(spTweetList, tweet.Id.ToString()) == false)
                            } // foreach (var tweet in tweets)

                            Logger.LogInfoLocal(EventId.Information, CategoryId.None, "Twitter account '" + account + "' was successfully archived.");
                        }
                        else
                        {
                            // No tweets to archive
                            Logger.LogInfoLocal(EventId.Information, CategoryId.None, "Twitter account '" + account + "' does not have any tweets.");
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.LogErrorLocal(EventId.Error, CategoryId.Error, ErrorLevel.High, "Twitter account '" + account + "' could not be archived due to error.", ex);
                    }

                } // foreach (string account in...
            } // if (tweetList != null)

            return tweetCount;
        }

        /// <summary>
        /// Checks to see if the tweet has already been archived.
        /// </summary>
        /// <param name="spArchivedTweetList">Reference to Archived Tweet list.</param>
        /// <param name="tweetId">Id of tweet to check.</param>
        /// <returns>True if already archived; false if otherwise.</returns>
        private bool doesArchivedTweetExist(SPList spArchivedTweetList, string tweetId)
        {
            string caml = string.Format("<Where><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">{0}</Value></Eq></Where>", tweetId);
            var query = new SPQuery()
            {
                Query = caml
            };
            int count = spArchivedTweetList.GetItems(query).Count;

            return (count > 0);
        }

        /// <summary>
        /// Checks to see if the Twitter Account name has already been archived.
        /// </summary>
        /// <param name="spArchivedAccountList">Reference to Archived Twitter Account list.</param>
        /// <param name="account">Name of account to check.</param>
        /// <returns>True if already archived; false if otherwise.</returns>
        private bool doesArchivedAccountExist(SPList spArchivedAccountList, string account)
        {
            string caml = string.Format("<Where><Eq><FieldRef Name=\"Screen_x0020_Name\" /><Value Type=\"Text\">{0}</Value></Eq></Where>", account);
            var query = new SPQuery()
            {
                Query = caml
            };
            int count = spArchivedAccountList.GetItems(query).Count;

            return (count > 0);
        }
    }
}
